using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using GrapeCity.Forguncy.Commands;
using GrapeCity.Forguncy.Plugin;
using iTextSharp.text.pdf;

namespace PdfOperationCommand
{
    [Icon("pack://application:,,,/PdfOperationCommand;component/Resources/Safety.png")]
    [OrderWeight(5)]
    [Description("保护PDF文件，使用iTextSharp实现")]
    public class PdfProtectionServerCommand : BaseServerCommand, ICommandExecutableInServerSideAsync
    {
        [Required]
        [FormulaProperty]
        [DisplayName("文件路径")]
        [Description("文件绝对路径，如：D:\\example.pdf(Windows)，/path/example.pdf(Linux)")]
        public object FilePath { get; set; }

        [DisplayName("PDF加密或解密")]
        [Description("PDF加密或解密")]
        public PdfProtectionType PdfProtectionType { get; set; }

        [Required]
        [FormulaProperty]
        [DisplayName("加密或解密密码")]
        [Description("加密或解密密码")]
        public object OwnerPassword { get; set; }

        [Required]
        [FormulaProperty]
        [DisplayName("输出文件路径")]
        [Description("文件绝对路径，如：D:\\example.pdf(Windows)，/path/example.pdf(Linux)")]
        public object OutFilePath { get; set; }

        public async Task<ExecuteResult> ExecuteAsync(IServerCommandExecuteContext dataContext)
        {
            var filePath = await GetParamValue(dataContext, FilePath);
            var outFilePath = await GetParamValue(dataContext, OutFilePath);
            var ownerPassword = await GetParamValue(dataContext, OwnerPassword);
            switch (PdfProtectionType)
            {
                case PdfProtectionType.Encryption:
                    EncryptPdf(filePath.ToString(), outFilePath.ToString(), ownerPassword.ToString());
                    break;
                case PdfProtectionType.Decryption:
                    DecryptPdf(filePath.ToString(), outFilePath.ToString(), ownerPassword.ToString());
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            return new ExecuteResult();
        }

        private void EncryptPdf(string inputFilePath, string outputFilePath, string ownerPassword)
        {
            using var inputPdf = new FileStream(inputFilePath, FileMode.Open);
            using var outputPdf = new FileStream(outputFilePath, FileMode.Create);
            using var reader = new PdfReader(inputPdf);
            using var stamper = new PdfStamper(reader, outputPdf);

            stamper.SetEncryption(
                userPassword: Encoding.ASCII.GetBytes(ownerPassword),
                ownerPassword: Encoding.ASCII.GetBytes(ownerPassword),
                permissions: PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_COPY,
                encryptionType: PdfWriter.ENCRYPTION_AES_128
            );

            stamper.Close();
            reader.Close();
        }

        private void DecryptPdf(string inputFilePath, string outputFilePath, string ownerPassword)
        {
            using var inputPdf = new PdfReader(inputFilePath, new ASCIIEncoding().GetBytes(ownerPassword));
            using var outputPdf = new FileStream(outputFilePath, FileMode.Create);
            using var reader = new PdfReader(inputPdf);
            using var stamper = new PdfStamper(reader, outputPdf);
            stamper.Close();
            reader.Close();
        }

        public override string ToString()
        {
            return "保护PDF文件";
        }
    }

    public enum PdfProtectionType
    {
        [Description("加密")] Encryption,
        [Description("解密")] Decryption,
    }
}